﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BonsaiScrum.Bus;

namespace BonsaiScrum.Core.BusImpl
{
    public class InProcessBus<T> : IBus<T> where T : IMessage
    {
        private readonly IRouteMessages _routeMessages;
        private readonly object _lockObject = new object();
        private readonly Queue<T> _preCommitQueue;
        private readonly InMemoryQueue _postCommitQueue;

        protected InProcessBus(IRouteMessages routeMessages)
        {
            _routeMessages = routeMessages;
            _preCommitQueue = new Queue<T>(32);
            _postCommitQueue = new InMemoryQueue();
            _postCommitQueue.Pop(DoPublish);
        }

        public void Publish(T message)
        {
            if (message == null)
                throw new ArgumentNullException("message");

            OnMessageReceived(message);

            lock (_lockObject)
            {
                _preCommitQueue.Enqueue(message);
            }
        }

        protected virtual void OnMessageReceived(T message) { }

        private void DoPublish(IMessage message)
        {
            try
            {
                _routeMessages.Route(message);
            }
            finally
            {
                _postCommitQueue.Pop(DoPublish);
            }
        }

        public void Commit()
        {
            lock (_lockObject)
            {
                while (_preCommitQueue.Count > 0)
                {
                    _postCommitQueue.Put(_preCommitQueue.Dequeue());
                }
            }
        }

        public void Rollback()
        {
            lock (_lockObject)
            {
                _preCommitQueue.Clear();   
            }
        }
    }
}
